#region Using directives

/*
 * Copyright (c) 2007 Alan Dean.
 * All rights released.
 */

using System;
using System.Globalization;
using System.Security.Permissions;
using System.Text;

using Edenbrook;
using Edenbrook.Globalization;

#endregion

namespace Edenbrook.Telephony
{
    #region Overview
    /// <summary>
    /// Represents a text message.
    /// <para>This class cannot be inherited.</para>
    /// </summary>
    /// 
    /// <remarks>None</remarks>
    /// 
    /// <permission cref="T:System.Security.Permissions.StrongNameIdentityPermission">
    /// Callers must be signed with the Edenbrook strong name key.
    /// </permission>
    #endregion
    [StrongNameIdentityPermission(SecurityAction.Demand, PublicKey = PublicKey.Value)]
    public sealed class TextMessage
    {
        // public constructors

        #region public TextMessage()
        /// <overloads>
        /// Initializes a new instance of the <see cref="T:Edenbrook.Telephony.TextMessage"/> class.
        /// </overloads>
        /// 
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Edenbrook.Telephony.TextMessage"/> class.
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        public TextMessage()
            : this(new StandardKeypad())
        { }
        #endregion

        #region public TextMessage(IKeypad)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Edenbrook.Telephony.TextMessage"/> class
        /// with the specified <paramref name="keypad"/>.
        /// </summary>
        /// 
        /// <param name="keypad">The keypad to use for this message.</param>
        /// 
        /// <remarks>None</remarks>
        public TextMessage(IKeypad keypad)
        {
            Keypad = keypad;

            _buffer = new StringBuilder();
        }
        #endregion

        // public properties

        #region public int ElapsedTime
        /// <summary>
        /// Gets the elapsed time for entering this message
        /// into the current <see cref="P:Edenbrook.Telephony.TextMessage.Keypad"/>.
        /// </summary>
        /// 
        /// <value>
        /// The elapsed time for entering this message.
        /// </value>
        /// 
        /// <remarks>None</remarks>
        public int ElapsedTime
        {
            get
            {
                return _elapsedTime;
            }
            private set
            {
                if (value < 0) throw ExceptionFactory.NumberNegative("elapsedTime", value);

                _elapsedTime = value;
            }
        }

        /// <summary>
        /// Stores the <see cref="P:Edenbrook.Telephony.TextMessage.Keypad"/> data
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        private int _elapsedTime;
        #endregion

        #region public IKeypad Keypad
        /// <summary>
        /// Gets the current keypad.
        /// </summary>
        /// 
        /// <value>
        /// The current keypad.
        /// </value>
        /// 
        /// <remarks>None</remarks>
        public IKeypad Keypad
        {
            get
            {
                return _keypad;
            }
            private set
            {
                if (value == null) throw ExceptionFactory.ObjectNull("keypad");

                _keypad = value;
            }
        }

        /// <summary>
        /// Stores the <see cref="P:Edenbrook.Telephony.TextMessage.Keypad"/> data
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        private IKeypad _keypad;
        #endregion

        // public methods (Object)

        #region public override string ToString()
        /// <summary>
        /// Returns a <see langword="string"/> that represents the current instance.
        /// </summary>
        /// 
        /// <returns>
        /// A <see langword="string"/> that represents the current instance.
        /// </returns>
        /// 
        /// <remarks>None</remarks>
        public override string ToString()
        {
            return _buffer.ToString();
        }

        /// <summary>
        /// Stores the data buffer for this instance.
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        private StringBuilder _buffer = null;
        #endregion

        // public methods

        #region public void Append(char)
        /// <summary>
        /// Appends the specified <paramref name="value"/> to this instance.
        /// </summary>
        /// 
        /// <param name="value">The character to append.</param>
        /// 
        /// <remarks>None</remarks>
        /// 
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Thrown when an invalid <paramref name="value"/> is specified.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown when an attempt to append more than 160 characters is made.
        /// </exception>
        public void Append(char value)
        {
            if (_buffer.Length > 159) throw ExceptionFactory.MessageLength(160);

            ElapsedTime += Keypad.Enter(value);

            _buffer.Append(value);
        }
        #endregion

        #region public void Append(string)
        /// <summary>
        /// Appends the specified <paramref name="value"/> to this instance.
        /// </summary>
        /// 
        /// <param name="value">The <see langword="string"/> to append.</param>
        /// 
        /// <remarks>None</remarks>
        /// 
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Thrown when an invalid <paramref name="value"/> is specified.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown when an attempt to append more than 160 characters is made.
        /// </exception>
        public void Append(string value)
        {
            if (!String.IsNullOrEmpty(value))
            {
                if ((_buffer.Length + value.Length) > 160) throw ExceptionFactory.MessageLength(160);

                ElapsedTime += Keypad.Enter(value);

                _buffer.Append(value);
            }
        }
        #endregion
    }
}